package com.ewei.web.common.email;

import java.io.File;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Message.RecipientType;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.task.TaskExecutor;

import com.ewei.web.common.email.auth.MailAuthenticator;
import com.ewei.web.common.exception.MessageRuntimeException;

/**
 * 电子邮件业务
 * @author David
 *
 */
public class EmailService implements EmailApi {
	private static final Logger logger = LogManager.getLogger(EmailService.class);
	//email会话
	private Session session = null;
	
	//是否使用taskExecutor
	private boolean useExecutor = false;
	
	private TaskExecutor executor = null;
	
	public EmailService(){
		//no parameter
	}
	public EmailService(Properties cfgs,boolean isAuth){
		openSession(cfgs,isAuth);
	}
	
	public void openSessionIfNot(Properties cfgs,boolean isAuth){
		if(session == null){
			openSession(cfgs,isAuth);
		}
	}
	
	public void openSession(Properties cfgs,boolean isAuth){
		session = createSession(cfgs,isAuth);
		session.setDebug(true);
	}
	private Session createSession(Properties cfgs,boolean isAuth){
		String account = cfgs.getProperty("mail.account", "");
		String password = cfgs.getProperty("mail.password", "");
		Authenticator authen = null;
		//是否需要验证
		if(isAuth){
			authen = new MailAuthenticator(account,password);
		}
		return Session.getDefaultInstance(cfgs, authen);
	}
	@Override
	public void send(TransferParams params) {
		send(params, this.session);
	}

	@Override
	public void send(TransferParams params, Properties props) {
		Session custom = createSession(props,true);
		send(params,custom);
	}
	private void send(TransferParams params,Session session){
		if(null == session){
			throw new MessageRuntimeException("email's session doesn't open");
		}
		MimeMessage mime = new MimeMessage(session);
		ExecuteThread thread = null;
		try{
			mime.setSubject(params.getSubject());
			mime.setFrom(new InternetAddress(session.getProperty("mail.account")));
			for(String toAddress:params.getToAddress()){
				InternetAddress address = new InternetAddress(toAddress);
				mime.addRecipient(RecipientType.TO, address);
			}
			for(String ccAddress:params.getCcAddress()){
				InternetAddress address = new InternetAddress(ccAddress);
				mime.addRecipient(RecipientType.CC, address);
			}
			// add content body
			MimeMultipart mainPart = new MimeMultipart();
			MimeBodyPart textBody = new MimeBodyPart();
			textBody.setText(params.getContent());
			mainPart.addBodyPart(textBody);
			mainPart.setSubType("related");
			//content file
			if(params.isAttach()){
				Pattern pattern = Pattern.compile("(?<=[\\/])[^\\/]*$");
				for(String path:params.getFilePaths()){
					MimeBodyPart body = new MimeBodyPart();
					DataSource dataSource = new FileDataSource(new File(path));
					DataHandler handler = new DataHandler(dataSource);
					body.setDataHandler(handler);
					Matcher match = pattern.matcher(path);
					body.setFileName(match.group());
					mainPart.addBodyPart(body);
				}
			}
			mime.setContent(mainPart);
			thread = new ExecuteThread(mime);
		}catch(Exception e){
			logger.info(e);
		}finally{
			if(null!=thread){
				if(useExecutor&&executor!=null){
					executor.execute(thread);
				}else{
					new Thread(thread).start();
				}
			}
		}
	}
	private class ExecuteThread implements Runnable{
		MimeMessage mime = null;
		public ExecuteThread(MimeMessage mime){
			this.mime = mime;
		}
		@Override
		public void run() {
			try {
				Transport.send(mime);
			} catch (MessagingException e) {
				logger.info(e);
				e.printStackTrace();
			}
		}
		
	}
	
	public boolean isUseExecutor() {
		return useExecutor;
	}
	
	public void setUseExecutor(boolean useExecutor) {
		this.useExecutor = useExecutor;
	}
	
	public TaskExecutor getExecutor() {
		return executor;
	}
	
	public void setExecutor(TaskExecutor executor) {
		this.executor = executor;
	}
	
}
